--=======================================
--[[ 本地函数 ]]
--=======================================
-- 移除预制物(预制物,数量)
local function removeItem(item, num)
    if item.components.stackable then
        item.components.stackable:Get(num):Remove()
    else
        item:Remove()
    end
end

-- 拆解法杖的函数
local DESTSOUNDS =
{
    { --magic
        soundpath = "dontstarve/common/destroy_magic",
        ing = { "nightmarefuel", "livinglog" },
    },
    { --cloth
        soundpath = "dontstarve/common/destroy_clothing",
        ing = { "silk", "beefalowool" },
    },
    { --tool
        soundpath = "dontstarve/common/destroy_tool",
        ing = { "twigs" },
    },
    { --gem
        soundpath = "dontstarve/common/gem_shatter",
        ing = { "redgem", "bluegem", "greengem", "purplegem", "yellowgem", "orangegem" },
    },
    { --wood
        soundpath = "dontstarve/common/destroy_wood",
        ing = { "log", "boards" },
    },
    { --stone
        soundpath = "dontstarve/common/destroy_stone",
        ing = { "rocks", "cutstone" },
    },
    { --straw
        soundpath = "dontstarve/common/destroy_straw",
        ing = { "cutgrass", "cutreeds" },
    },
}
local DESTSOUNDSMAP = {}
for i, v in ipairs(DESTSOUNDS) do
    for i2, v2 in ipairs(v.ing) do
        DESTSOUNDSMAP[v2] = v.soundpath
    end
end
DESTSOUNDS = nil

local function CheckSpawnedLoot(loot)
    if loot.components.inventoryitem ~= nil then
        loot.components.inventoryitem:TryToSink()
    else
        local lootx, looty, lootz = loot.Transform:GetWorldPosition()
        if ShouldEntitySink(loot, true) or TheWorld.Map:IsPointNearHole(Vector3(lootx, 0, lootz)) then
            SinkEntity(loot)
        end
    end
end

local function SpawnLootPrefab(inst, lootprefab)
    if lootprefab == nil then
        return
    end

    local loot = SpawnPrefab(lootprefab)
    if loot == nil then
        return
    end

    local x, y, z = inst.Transform:GetWorldPosition()

    if loot.Physics ~= nil then
        local angle = math.random() * TWOPI
        loot.Physics:SetVel(2 * math.cos(angle), 10, 2 * math.sin(angle))

        if inst.Physics ~= nil then
            local len = loot:GetPhysicsRadius(0) + inst:GetPhysicsRadius(0)
            x = x + math.cos(angle) * len
            z = z + math.sin(angle) * len
        end

        loot:DoTaskInTime(1, CheckSpawnedLoot)
    end

    loot.Transform:SetPosition(x, y, z)

    loot:PushEvent("on_loot_dropped", { dropper = inst })

    return loot
end

local function destroystructure(tool, target)
    local recipe = AllRecipes[target.prefab]
    if recipe == nil or FunctionOrValue(recipe.no_deconstruction, target) then
        return false, "ASSN_DESTROY_FAIL"
    end

    local ingredient_percent =
        ((target.components.finiteuses ~= nil and target.components.finiteuses:GetPercent()) or
            (target.components.fueled ~= nil and target.components.inventoryitem ~= nil and target.components.fueled:GetPercent()) or
            (target.components.armor ~= nil and target.components.inventoryitem ~= nil and target.components.armor:GetPercent()) or
            1
        ) / recipe.numtogive

    local caster = tool.components.inventoryitem.owner

    if target.components.itemmimic then
        if caster then
            caster.SoundEmitter:PlaySound("dontstarve/creatures/monkey/poopsplat")
        end
        target.components.itemmimic:TurnEvil(caster)
    else
        for i, v in ipairs(recipe.ingredients) do
            if caster ~= nil and DESTSOUNDSMAP[v.type] ~= nil then
                caster.SoundEmitter:PlaySound(DESTSOUNDSMAP[v.type])
            end
            if string.sub(v.type, -3) ~= "gem" or string.sub(v.type, -11, -4) == "precious" then
                local amt = v.amount == 0 and 0 or math.max(1, math.ceil(v.amount * ingredient_percent))
                for _ = 1, amt do
                    SpawnLootPrefab(target, v.type)
                end
            end
        end

        if target.components.inventory ~= nil then
            target.components.inventory:DropEverything()
        end

        if target.components.container ~= nil then
            target.components.container:DropEverything(nil, true)
        end

        if target.components.spawner ~= nil and target.components.spawner:IsOccupied() then
            target.components.spawner:ReleaseChild()
        end

        if target.components.occupiable ~= nil and target.components.occupiable:IsOccupied() then
            local item = target.components.occupiable:Harvest()
            if item ~= nil then
                item.Transform:SetPosition(target.Transform:GetWorldPosition())
                item.components.inventoryitem:OnDropped()
            end
        end

        if target.components.trap ~= nil then
            target.components.trap:Harvest()
        end

        if target.components.dryer ~= nil then
            target.components.dryer:DropItem()
        end

        if target.components.harvestable ~= nil then
            target.components.harvestable:Harvest()
        end

        if target.components.stewer ~= nil then
            target.components.stewer:Harvest()
        end

        if target.components.constructionsite ~= nil then
            target.components.constructionsite:DropAllMaterials()
        end

        if target.components.inventoryitemholder ~= nil then
            target.components.inventoryitemholder:TakeItem()
        end

        target:PushEvent("ondeconstructstructure", caster)

        if not target.no_delete_on_deconstruct then
            if target.components.stackable ~= nil then
                target.components.stackable:Get():Remove()
            else
                target:Remove()
            end
        end
    end

    if caster ~= nil then
        caster.SoundEmitter:PlaySound("dontstarve/common/staff_dissassemble")
    end

    if tool.components.qianrengrowth.level < 10 then
        tool.components.fueled:DoDelta(-50) -- 每次射击消耗50点燃料
    else
        tool.components.fueled:DoDelta(-1)  -- 每次射击消耗1点燃料
    end
    return true
end
--=======================================
--[[ 动作定义 ]]
--=======================================
local actions = {
    ASSN_FIX = {
        id = "ASSN_FIX",
        priority = 6,
        strfn = function(act)
            return "GENERIC"
        end,
        fn = function(act)
            if act.target.components.finiteuses then
                local old_percent = act.target.components.finiteuses:GetPercent()
                if old_percent >= 1 then
                    return false, "ASSN_FIX_FULL"
                end
                local new_percent = old_percent + 0.2
                if new_percent > 1 then
                    new_percent = 1
                end
                act.target.components.finiteuses:SetPercent(new_percent)
                removeItem(act.invobject)
                return true
            elseif act.target.components.fueled then
                local old_percent = act.target.components.fueled:GetPercent()
                if old_percent >= 1 then
                    return false, "ASSN_FIX_FULL"
                end
                local new_percent = old_percent + 0.2
                if new_percent > 1 then
                    new_percent = 1
                end
                act.target.components.fueled:SetPercent(new_percent)
                removeItem(act.invobject)
                return true
            elseif act.target.components.armor then
                local old_percent = act.target.components.armor:GetPercent()
                if old_percent >= 1 then
                    return false, "ASSN_FIX_FULL"
                end
                local new_percent = old_percent + 0.2
                if new_percent > 1 then
                    new_percent = 1
                end
                act.target.components.armor:SetPercent(new_percent)
                removeItem(act.invobject)
                return true
            else
                return false, "ASSN_FIX_FAIL"
            end
        end,
    },
    ASSN_DESTROY = {
        id = "ASSN_DESTROY",
        priority = 6,
        strfn = function(act)
            return "GENERIC"
        end,
        fn = function(act)
            return destroystructure(act.invobject, act.target)
        end,
    },
    ASSN_CHARGING = {
        id = "ASSN_CHARGING",
        priority = 6,
        strfn = function(act)
            return "GENERIC"
        end,
        fn = function(act)
            local target = act.target
            if target.components.timer ~= nil and target.components.timer:TimerExists("damageover") then
                local old_time = target.components.timer:GetTimeLeft("damageover")
                local new_time = math.min(300, old_time + 60)
                target.components.timer:SetTimeLeft("damageover", new_time)
            else
                target.components.timer:StartTimer("damageover", 60)
            end
            target.components.qianrengrowth.add_damage = 20
            target.components.qianrengrowth:UpdateWeaponDamage()
            if act.invobject.prefab == "assn_suipian" then
                target.components.qianrengrowth:AddExp(2)
            else
                target.components.qianrengrowth:AddExp(1)
            end
            target.SoundEmitter:PlaySound("dontstarve/common/nightmareAddFuel")
            removeItem(act.invobject)
            return true
        end,
    },
    ASSN_FUEL = {
        id = "ASSN_FUEL",
        priority = 6,
        strfn = function(act)
            return "GENERIC"
        end,
        fn = function(act)
            local target = act.target
            local item = act.invobject
            if item and item.components.assn_fuel and item.components.assn_fuel.fuelvalue then
                target.components.fueled:DoDelta(item.components.assn_fuel.fuelvalue)
                if item.prefab == "nightmarefuel" then
                    if target.components.qianrengrowth ~= nil then
                        target.components.qianrengrowth:AddExp(1)
                        target.SoundEmitter:PlaySound("dontstarve/common/nightmareAddFuel")
                    end
                end
                removeItem(act.invobject)
                return true
            end
        end,
    },
}

for _, action in pairs(actions) do
    local _action = Action()
    for k, v in pairs(action) do
        _action[k] = v
    end
    AddAction(_action)
end

--=======================================
--[[ 动作行为:就是执行动作的人物动画 ]]
--=======================================
AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.ASSN_FIX, "domediumaction"))
AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.ASSN_FIX, "domediumaction"))

AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.ASSN_DESTROY, "dolongaction"))
AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.ASSN_DESTROY, "dolongaction"))

AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.ASSN_CHARGING, "doshortaction"))
AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.ASSN_CHARGING, "doshortaction"))

AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.ASSN_FUEL, "doshortaction"))
AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.ASSN_FUEL, "doshortaction"))

--=======================================
--[[ ADD COMPONENT ACTION ]]
-- SCENE		using an object in the world                                        --args: inst, doer, actions, right
-- USEITEM		using an inventory item on an object in the world                   --args: inst, doer, target, actions, right
-- POINT		using an inventory item on a point in the world                     --args: inst, doer, pos, actions, right, target
-- EQUIPPED		using an equiped item on yourself or a target object in the world   --args: inst, doer, target, actions, right
-- INVENTORY	using an inventory item                                             --args: inst, doer, actions, right
--=======================================

-- target是对象,inst是手中或鼠标上物品,doer是做动作的玩家,right是是否为右键
AddComponentAction("USEITEM", "assn_fix", function(inst, doer, target, actions, right)
    if inst:HasTag("assn_suipian") then
        table.insert(actions, ACTIONS.ASSN_FIX)
    end
end)

AddComponentAction("USEITEM", "assn_destroy", function(inst, doer, target, actions, right)
    if inst:HasTag("assn_jiandao") and (not inst:HasTag("thrown")) then
        table.insert(actions, ACTIONS.ASSN_DESTROY)
    end
end)

AddComponentAction("USEITEM", "inventoryitem", function(inst, doer, target, actions, right)
    if (inst.prefab == "assn_suipian" or inst.prefab == "nightmarefuel" or inst:HasTag("weapon")) and target:HasTag("assn_qianren") then
        table.insert(actions, ACTIONS.ASSN_CHARGING)
    end
end)

AddComponentAction("USEITEM", "assn_fuel", function(inst, doer, target, actions, right)
    if inst:HasTag("ASSN_JIANDAO") and target:HasTag("assn_jiandao") then
        table.insert(actions, ACTIONS.ASSN_FUEL)
    end
end)

-- 动作兼容行为排队论
local queueractlist = {
    ASSN_CHARGING = "allclick",
    ASSN_FUEL = "allclick",
}
local actionqueuer_status, actionqueuer_data = pcall(require, "components/actionqueuer")
if actionqueuer_status then
    if AddActionQueuerAction and next(queueractlist) then
        for k, v in pairs(queueractlist) do
            AddActionQueuerAction(v, k, true)
        end
    end
end
